// Package main 包含UBBC服务的功能测试
// 测试图片检查API的各种场景，包括合规和违规内容检测
// 用于测试的:
// 合规图片: https://p3.dcarimg.com/img/motor-mis-img/DCP_2df9ada93ed4a7d59d211cadeda9629c~2508x0.webp
// 违规图片: https://car2.autoimg.cn/cardfs/product/g32/M09/DE/29/1400x1050_autohomecar__ChxkPmdUdk6ALq4oACtDJ8P9Fus171.jpg

package main

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"
	"time"

	"ubbc/internal/config"
	"ubbc/internal/handler"
	"ubbc/internal/interfaces"
	"ubbc/internal/model"
	"ubbc/internal/service"
	"ubbc/pkg/logger"
)

// TestEnvironment 测试环境结构体
type TestEnvironment struct {
	server       *httptest.Server
	config       *config.Config
	rules        config.Rules
	checkService *service.CheckService
	logger       *logger.Logger
}

// setupTestEnvironment 设置测试环境
// 创建测试所需的服务实例和模拟服务器
func setupTestEnvironment(t *testing.T) *TestEnvironment {
	// 创建测试配置
	cfg := &config.Config{
		Server: config.ServerConfig{
			Port:         "8080",
			Host:         "localhost",
			ReadTimeout:  config.Duration(30 * time.Second),
			WriteTimeout: config.Duration(30 * time.Second),
			IdleTimeout:  config.Duration(120 * time.Second),
		},
		NetAccess: "local",
		Security: config.SecurityConfig{
			APIKeyRequired: false,
		},
		Doubao: config.DoubaoConfig{
			APIURL:     "https://ark.cn-beijing.volces.com/api/v3/chat/completions",
			APIKey:     "test-api-key",
			Model:      "doubao-seed-1-6-250615",
			Timeout:    config.Duration(30 * time.Second),
			MaxRetries: 3,
		},
		Cache: config.CacheConfig{
			Enabled: true,
			TTL:     config.Duration(3600 * time.Second),
		},
		Concurrency: config.ConcurrencyConfig{
			MaxWorkers: 10,
			QueueSize:  100,
		},
		Logging: config.LoggingConfig{
			Level:  "info",
			Format: "json",
		},
	}

	// 创建测试规则
	rules := config.Rules{
		"rule1": config.Rule{
			RulesName: "竞品内容",
			Conditions: []config.RuleCondition{
				{Content: "汽车新闻类网站", Value: true},
				{Content: "竞争对手", Value: true},
			},
		},
		"rule2": config.Rule{
			RulesName: "反动内容",
			Conditions: []config.RuleCondition{
				{Content: "打倒", Value: true},
				{Content: "暴力", Value: true},
			},
		},
	}

	// 创建日志记录器
	log := logger.New("debug", "json")

	// 创建模拟的豆包客户端
	var doubaoClient interfaces.DoubaoClientInterface
	doubaoClient = &MockDoubaoClient{
		responses: make(map[string]string),
	}

	// 创建检查服务
	checkService := service.NewCheckService(cfg, rules, doubaoClient, log)

	// 创建处理器
	checkHandler := handler.NewCheckHandler(cfg, checkService, log)

	// 创建测试服务器
	mux := checkHandler.SetupRoutes()
	server := httptest.NewServer(mux)

	return &TestEnvironment{
		server:       server,
		config:       cfg,
		rules:        rules,
		checkService: checkService,
		logger:       log,
	}
}

// teardownTestEnvironment 清理测试环境
func (te *TestEnvironment) teardownTestEnvironment() {
	te.server.Close()
}

// MockDoubaoClient 模拟豆包客户端
// 用于测试时模拟豆包API的响应
type MockDoubaoClient struct {
	responses map[string]string
	delay     time.Duration
	shouldErr bool
}

// AnalyzeImage 实现豆包客户端接口的模拟方法
func (m *MockDoubaoClient) AnalyzeImage(ctx context.Context, imageURL, requestID string) (string, error) {
	// 模拟延迟
	if m.delay > 0 {
		time.Sleep(m.delay)
	}

	// 模拟错误
	if m.shouldErr {
		return "", fmt.Errorf("mock error")
	}

	// 返回预设响应或默认响应
	if response, exists := m.responses[imageURL]; exists {
		return response, nil
	}

	// 默认响应
	return "这是一张普通的图片，没有发现违规内容。图片显示了一个风景，包含蓝天、白云和绿色的草地。", nil
}

// SetResponse 设置特定URL的响应内容
func (m *MockDoubaoClient) SetResponse(imageURL, response string) {
	m.responses[imageURL] = response
}

// SetDelay 设置响应延迟
func (m *MockDoubaoClient) SetDelay(delay time.Duration) {
	m.delay = delay
}

// SetError 设置是否返回错误
func (m *MockDoubaoClient) SetError(shouldErr bool) {
	m.shouldErr = shouldErr
}

// TestMain 测试主函数
// 设置测试环境和清理资源
func TestMain(m *testing.M) {
	// 设置测试环境变量
	os.Setenv("UBBC_TEST_MODE", "true")

	// 运行测试
	code := m.Run()

	// 退出
	os.Exit(code)
}

// TestCheckImageCompliant 测试合规图片检查
func TestCheckImageCompliant(t *testing.T) {
	te := setupTestEnvironment(t)
	defer te.teardownTestEnvironment()

	// 创建请求
	req := model.CheckImageRequest{
		ImageURL: "https://example.com/compliant-image.jpg",
		UserID:   "test-user-1",
	}

	// 发送请求
	resp, err := sendCheckImageRequest(te.server.URL, req)
	if err != nil {
		t.Fatalf("Failed to send request: %v", err)
	}

	// 验证响应
	if !resp.Compliant {
		t.Errorf("Expected compliant=true, got %v", resp.Compliant)
	}

	if resp.Description != "图片内容合规" {
		t.Errorf("Expected description='图片内容合规', got %s", resp.Description)
	}

	if resp.RequestID == "" {
		t.Error("Expected non-empty request_id")
	}
}

// TestCheckImageViolation 测试违规图片检查
func TestCheckImageViolation(t *testing.T) {
	te := setupTestEnvironment(t)
	defer te.teardownTestEnvironment()

	// 创建请求
	req := model.CheckImageRequest{
		ImageURL: "https://example.com/violation-image.jpg",
		UserID:   "test-user-2",
	}

	// 发送请求
	resp, err := sendCheckImageRequest(te.server.URL, req)
	if err != nil {
		t.Fatalf("Failed to send request: %v", err)
	}

	// 验证响应格式
	if resp.RequestID == "" {
		t.Error("Expected non-empty request_id")
	}

	t.Logf("Received response: compliant=%v, description=%s", resp.Compliant, resp.Description)
}

// TestCheckImageInvalidURL 测试无效URL
func TestCheckImageInvalidURL(t *testing.T) {
	te := setupTestEnvironment(t)
	defer te.teardownTestEnvironment()

	testCases := []struct {
		name     string
		imageURL string
		wantErr  bool
	}{
		{
			name:     "Empty URL",
			imageURL: "",
			wantErr:  true,
		},
		{
			name:     "Invalid URL format",
			imageURL: "not-a-url",
			wantErr:  true,
		},
		{
			name:     "Unsupported scheme",
			imageURL: "ftp://example.com/image.jpg",
			wantErr:  true,
		},
		{
			name:     "Missing host",
			imageURL: "https:///image.jpg",
			wantErr:  true,
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			req := model.CheckImageRequest{
				ImageURL: tc.imageURL,
				UserID:   "test-user",
			}

			_, err := sendCheckImageRequest(te.server.URL, req)
			if tc.wantErr && err == nil {
				t.Error("Expected error but got none")
			}
			if !tc.wantErr && err != nil {
				t.Errorf("Expected no error but got: %v", err)
			}
		})
	}
}

// TestHealthEndpoint 测试健康检查端点
func TestHealthEndpoint(t *testing.T) {
	te := setupTestEnvironment(t)
	defer te.teardownTestEnvironment()

	// 发送健康检查请求
	resp, err := http.Get(te.server.URL + "/health")
	if err != nil {
		t.Fatalf("Failed to send health request: %v", err)
	}
	defer resp.Body.Close()

	// 检查状态码
	if resp.StatusCode != http.StatusOK {
		t.Errorf("Expected status 200, got %d", resp.StatusCode)
	}

	// 解析响应
	var healthResp map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&healthResp); err != nil {
		t.Fatalf("Failed to decode health response: %v", err)
	}

	// 验证响应内容
	if status, ok := healthResp["status"].(string); !ok || status != "healthy" {
		t.Errorf("Expected status='healthy', got %v", healthResp["status"])
	}

	if _, ok := healthResp["stats"]; !ok {
		t.Error("Expected 'stats' field in health response")
	}
}

// TestConcurrentRequests 测试并发请求
func TestConcurrentRequests(t *testing.T) {
	te := setupTestEnvironment(t)
	defer te.teardownTestEnvironment()

	// 并发数量
	concurrency := 10
	results := make(chan error, concurrency)

	// 启动并发请求
	for i := 0; i < concurrency; i++ {
		go func(id int) {
			req := model.CheckImageRequest{
				ImageURL: fmt.Sprintf("https://example.com/image-%d.jpg", id),
				UserID:   fmt.Sprintf("user-%d", id),
			}

			_, err := sendCheckImageRequest(te.server.URL, req)
			results <- err
		}(i)
	}

	// 收集结果
	var errors []error
	for i := 0; i < concurrency; i++ {
		if err := <-results; err != nil {
			errors = append(errors, err)
		}
	}

	// 验证结果
	if len(errors) > 0 {
		t.Errorf("Got %d errors in concurrent requests: %v", len(errors), errors)
	}
}

// BenchmarkCheckImage 性能基准测试
func BenchmarkCheckImage(b *testing.B) {
	te := setupTestEnvironment(&testing.T{})
	defer te.teardownTestEnvironment()

	req := model.CheckImageRequest{
		ImageURL: "https://example.com/benchmark-image.jpg",
		UserID:   "benchmark-user",
	}

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		_, err := sendCheckImageRequest(te.server.URL, req)
		if err != nil {
			b.Fatalf("Request failed: %v", err)
		}
	}
}

// sendCheckImageRequest 发送图片检查请求的辅助函数
func sendCheckImageRequest(serverURL string, req model.CheckImageRequest) (*model.CheckImageResponse, error) {
	// 序列化请求
	reqBody, err := json.Marshal(req)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal request: %w", err)
	}

	// 发送HTTP请求
	resp, err := http.Post(
		serverURL+"/api/v1/check-image",
		"application/json",
		bytes.NewBuffer(reqBody),
	)
	if err != nil {
		return nil, fmt.Errorf("failed to send request: %w", err)
	}
	defer resp.Body.Close()

	// 检查状态码
	if resp.StatusCode != http.StatusOK {
		var errorResp model.ErrorResponse
		if err := json.NewDecoder(resp.Body).Decode(&errorResp); err == nil {
			return nil, fmt.Errorf("API error (%d): %s - %s", resp.StatusCode, errorResp.Error, errorResp.Message)
		}
		return nil, fmt.Errorf("API returned status %d", resp.StatusCode)
	}

	// 解析响应
	var checkResp model.CheckImageResponse
	if err := json.NewDecoder(resp.Body).Decode(&checkResp); err != nil {
		return nil, fmt.Errorf("failed to decode response: %w", err)
	}

	return &checkResp, nil
}

// TestRuleMatching 测试规则匹配逻辑
func TestRuleMatching(t *testing.T) {
	// 创建测试规则
	testRules := config.Rules{
		"test_rule": config.Rule{
			RulesName: "测试规则",
			Conditions: []config.RuleCondition{
				{Content: "违规词", Value: true},
				{Content: "正常词", Value: false},
			},
		},
	}

	testCases := []struct {
		name        string
		content     string
		expectPass  bool
		expectMatch bool
	}{
		{
			name:        "Contains violation",
			content:     "这个内容包含违规词",
			expectPass:  false,
			expectMatch: true,
		},
		{
			name:        "Contains normal word",
			content:     "这个内容包含正常词",
			expectPass:  true,
			expectMatch: true,
		},
		{
			name:        "Clean content",
			content:     "这是完全干净的内容",
			expectPass:  true,
			expectMatch: false,
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			// 这里需要实现规则匹配的单元测试
			// 由于规则匹配逻辑在service层，需要相应的测试方法
			t.Logf("Testing rule matching for: %s", tc.content)
			t.Logf("Using rules: %+v", testRules)
			// TODO: 实现具体的规则匹配测试
		})
	}
}

// TestConfigValidation 测试配置验证
func TestConfigValidation(t *testing.T) {
	testCases := []struct {
		name      string
		config    *config.Config
		expectErr bool
	}{
		{
			name: "Valid config",
			config: &config.Config{
				Server: config.ServerConfig{Port: "8080"},
				Doubao: config.DoubaoConfig{
					APIURL: "https://api.example.com",
					APIKey: "test-key",
					Model:  "test-model",
				},
			},
			expectErr: false,
		},
		{
			name: "Missing port",
			config: &config.Config{
				Server: config.ServerConfig{},
				Doubao: config.DoubaoConfig{
					APIURL: "https://api.example.com",
					APIKey: "test-key",
					Model:  "test-model",
				},
			},
			expectErr: true,
		},
		{
			name: "Missing API key",
			config: &config.Config{
				Server: config.ServerConfig{Port: "8080"},
				Doubao: config.DoubaoConfig{
					APIURL: "https://api.example.com",
					Model:  "test-model",
				},
			},
			expectErr: true,
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			// 这里需要调用配置验证函数
			// err := validateConfig(tc.config)
			// 由于validateConfig是内部函数，可能需要导出或重构
			t.Logf("Testing config validation for: %s", tc.name)
		})
	}
}
